/// -*- c++ -*-
/// Example wrapper script for wrap.py
/// by Todd Gamblin tgamblin@llnl.gov
///
/// This shows sample usage of many of the builtin macros in the wrapper generator.
///
/// Run it through wrap.py like this to see sample output:
///     wrap.py -o output.txt example.w
///
/// Note that this won't compile; this file is just a simple tutorial with examples.
///

// Say you just want to generate wrappers for some functions.  That's easy with fn and fnall.
// This simple formulation will generate wrappers for MPI_Send and MPI_Recv:
{{fn foo MPI_Send MPI_Recv}}
  {{callfn}}
{{endfn}}

// Usually, we add some braces to that so that the editor gets the indentation right  You
// don't *need* the braces, but they look nice and help emacs understand where your nested
// scopes are in C mode.
{{fn foo MPI_Send MPI_Recv}} {
  {{callfn}}
}
{{endfn}}

// If you generate this file and look at the output, you'll see full wrapper functions for
// MPI_Send and MPI_Recv.  The 'callfn' macro tells the wrapper generator to generate a
// delegating call from MPI_Send (or MPI_Recv) to PMPI_Send (or PMPI_Recv).  That's all
// it takes!  All the cruft is handled for you by wrap.py.

// But what's that 'foo' above, you say?  foo is your "loop variable".  It can be used
// to refer to the name of the function inside the wrapper:
{{fn foo MPI_Send MPI_Recv}} {
  // 'foo' here evaluates to just the name of the function.
  my_global_function_pointer = {{foo}};
}
{{endfn}}

// Usually you'll want to insert your own code in the wrappers.  Say you wanted to time
// every MPI function.  You could use 'fnall'.  Note that with fnall, the functions you
// list after the loop variable are *excluded* from generation.  So this will generate
// wrappers for every MPI function *except* MPI_Send and MPI_Recv:
{{fnall foo MPI_Send MPI_Recv}} {
  double start_time = get_time_in_nanoseconds();
  {{callfn}}
  double end_time = get_time_in_nanoseconds();
  printf("{{foo}} took %f nanoseconds to run!\n", (end_time - start_time));
}
{{endfnall}}

// Ok, so now you can make wrappers.  What if you want to iterate over all the MPI
// calls, but just their names, without generating wrappers?  There are macros for
// that too.

// foreachfn iterates over function names that wrap.py found in the mpi.h header.
// forallfn is like fnall, but it again iterates over everything *except* specified
// functions.
{{foreachfn foo MPI_Send MPI_Recv}} {
  // With foreachfn and forallfn, wrappers aren't generated by default.  You have
  // to put some macros in the nested scope to get something to happen.  Luckily,
  // in iterative constructs like fn, fnall, foreachfn, and forallfn, the wrapper
  // generator inserts special variables into the nested scope.  You can get at
  // them using macros like so:

  // The return type of the function (this is a simple string):
  {{ret_type}}

  // The name of the function (the name comes from the foreachfn "loop" macro above)
  {{foo}}

  // A unique number, starting at zero and increasing each time it is evaluated
  // this is a holdover from the MPE wrapper generator.
  {{fn_num}}

  // You can use regular expression substitutions on variables and print the result.
  // This, for example, renames MPI_ functions to have NQJ_ prefixes instead.  Here
  // it prints out either NQJ_Send or NQJ_Recv, depending on which iteration of the
  // foreachfn loop we're on.
  {{sub {{foo}} MPI_ NQJ_}}

  // You can rename things or define new values with def.
  // Note that def itself doesn't print anything:
  {{def my_var {{ret_type}}}}
  {{my_var}}

  // Suppose you wanted to substitute MPI for NQJ *once*, then use that value
  // repeatedly in this scope:
  {{def nqjfun {{sub {{foo}} MPI_ NQJ_}}}}
  {{nqjfun}}  {{nqjfun}}  {{nqjfun}}

  // Not everything in wrap.py is a scalar!  There are also list values.  These
  // are important for dealing with parameter lists and

  // Formal parameters:
  {{formals}}
  {{formals 0}}
  {{formals 1}}

  // Types of formals:
  {{types}}
  {{types 0}}
  {{types 1}}

  // Argument names:
  {{args}}
  {{args 0}}
  {{args 1}}
  // -- or --
  {{0}}
  {{1}}

  // Lists, when printed, are printed separated by commas.  This is so that you
  // can easily make lists of parameters or arguments out of them.  You can modify
  // the builtin lists using the 'list' macro, which creates or modifies lists.
  // Here are some examples using list:

  // Create a list of your own strings.  This prints out foo, bar, baz.
  {{list foo bar baz}}

  // Add newarg to the beginning of the args list and print the result:
  {{list newarg {{args}}}}

  // Add newarg to the end of the args list:
  {{list {{args}} newarg}}

  // Make a variable for the new list, then print it out:
  {{def new_list {{list {{args}} newarg}} }}
  {{new_list}}

  // Get a list of only those formal parameters that have MPI handle types:
  {{filter '^MPI_' {{formals}}}}

  // Below are some more complicated (but useful!) expressions.
  // Note that these use macros not fully explained here.  See the documentation
  // for details on what zip does or what sub does when applied to a list.

  // replace void with FOO in the first type in the parameter list
  {{sub {{types 0}} void FOO}}

  // replace void with FOO in all types in the parameter list
  {{sub {{types}} int FOO}}

  // replace void with FOO in all types in the parameter list,
  // and join that with the arg names for a new prototype
  {{ret_type}} {{foo}}({{zip {{sub {{types}} void FOO}} {{args}}}});

  // replace every parameter type with the return type
  {{ret_type}} {{foo}}({{zip {{sub {{types}} '.*' {{ret_type}}}} {{args}}}});

  // replace any MPI type with MPI_Foo in the parameter list
  {{ret_type}} {{foo}}({{zip {{sub {{types}} 'MPI_.*' MPI_Foo}} {{args}}}});


  // The apply_to_type macro generates code to apply a callable thing
  // (function, macro, functor) to every parameter of a particular type

  // This will generate analyze_comm(comm) calls for each MPI_Comm parameter
  {{apply_to_type MPI_Comm analyze_comm}}

  // This will call some_function on every int parameter to the call
  {{apply_to_type int some_function}}
}
{{endforeachfn}}



